import {message} from 'antd';
import { post } from './api';
import {API, JWT, STORAGE_KEYS} from '../constants';
import type {AuthResponse, RefreshTokenResponse, UserData} from '../types';

export interface DecodedToken {
    sub: string;
    username: string;
    role?: string;
    exp?: number;
    iat?: number;

    [key: string]: any;
}

// Token management functions
export const getToken = (): string | null => {
    return localStorage.getItem(STORAGE_KEYS.JWT_TOKEN);
};

export const setToken = (token: string, expiresIn?: number): void => {
    localStorage.setItem(STORAGE_KEYS.JWT_TOKEN, token);

    // If expiresIn is provided, store the expiration timestamp
    if (expiresIn) {
        const expiresAt = Date.now() + expiresIn * 1000;
        localStorage.setItem(STORAGE_KEYS.TOKEN_EXPIRES_AT, expiresAt.toString());
    }
};

export const removeToken = (): void => {
    localStorage.removeItem(STORAGE_KEYS.JWT_TOKEN);
    localStorage.removeItem(STORAGE_KEYS.TOKEN_EXPIRES_AT);
};

export const getRefreshToken = (): string | null => {
    return localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN);
};

export const setRefreshToken = (token: string): void => {
    localStorage.setItem(STORAGE_KEYS.REFRESH_TOKEN, token);
};

export const removeRefreshToken = (): void => {
    localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN);
};

// Decode JWT token without validation
export const decodeToken = (token: string): DecodedToken | null => {
    try {
        const base64Url = token.split('.')[1];
        const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
        const jsonPayload = decodeURIComponent(
            window
                .atob(base64)
                .split('')
                .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
                .join('')
        );
        return JSON.parse(jsonPayload);
    } catch (error) {
        console.error('Failed to decode token:', error);
        return null;
    }
};

export const isTokenExpired = (): boolean => {
    const token = getToken();
    if (!token) return true;

    // First check if we have stored expiration time
    const expiresAt = localStorage.getItem(STORAGE_KEYS.TOKEN_EXPIRES_AT);
    if (expiresAt) {
        // Add buffer time to ensure we refresh before actual expiration
        return Date.now() > Number(expiresAt) - JWT.TOKEN_EXPIRY_BUFFER;
    }

    // If no stored expiration, try to decode token and check exp claim
    try {
        const decoded = decodeToken(token);
        if (decoded && decoded.exp) {
            return Date.now() >= (decoded.exp * 1000) - JWT.TOKEN_EXPIRY_BUFFER;
        }
    } catch (error) {
        console.error('Error checking token expiration:', error);
    }

    // If we can't determine expiration, assume it's not expired
    return false;
};

export const isAuthenticated = (): boolean => {
    const token = getToken();
    if (!token) return false;

    // Check if token is expired
    if (isTokenExpired()) {
        // Try to refresh the token if it's expired
        const refreshTokenExists = !!getRefreshToken();
        if (!refreshTokenExists) {
            return false;
        }

        // We have a refresh token, but we'll let the interceptor handle the refresh
        // For now, return true to avoid interrupting the user experience
        return true;
    }

    return true;
};

export const getUserData = (): UserData | null => {
    const userData = localStorage.getItem(STORAGE_KEYS.USER);
    return userData ? JSON.parse(userData) : null;
};

export const setUserData = (user: UserData): void => {
    localStorage.setItem(STORAGE_KEYS.USER, JSON.stringify(user));
};

// Token refresh functionality
// let isRefreshing = false;
let refreshSubscribers: Array<(token: string) => void> = [];

export const subscribeToTokenRefresh = (callback: (token: string) => void): void => {
    refreshSubscribers.push(callback);
};

export const onTokenRefreshed = (token: string): void => {
    refreshSubscribers.forEach(callback => callback(token));
    refreshSubscribers = [];
};

export const refreshToken = async (): Promise<string | null> => {
    const refreshToken = getRefreshToken();
    
    if (!refreshToken) {
        return null;
    }
    
    try {
        const response = await post<RefreshTokenResponse>(API.AUTH.REFRESH_TOKEN, {refreshToken});
        
        if (response.success && response.data) {
            const {token: newToken, refreshToken: newRefreshToken, expiresIn} = response.data;
            setToken(newToken, expiresIn);
            
            if (newRefreshToken) {
                setRefreshToken(newRefreshToken);
            }
            
            onTokenRefreshed(newToken);
            return newToken;
        }
        
        return null;
    } catch (error) {
        console.error('Token refresh error:', error);
        return null;
    }
};

// Auth API functions
export const loginWithJWT = async (username: string, password: string): Promise<boolean> => {
    try {
        const response = await post<AuthResponse>(API.AUTH.LOGIN, {username, password});

        if (response.success && response.data && response.data.token) {
            const authData = response.data;

            // Store the JWT token with expiration if provided
            setToken(authData.token!, authData.expiresIn);

            if (authData.user) {
                setUserData(authData.user);
            } else {
                // If user data is not provided, try to extract from token
                const decoded = decodeToken(authData.token!);
                if (decoded) {
                    const userData: UserData = {
                        username: decoded.username || decoded.sub,
                        role: decoded.role || 'user',
                        permissions:decoded.permissions || [],
                        status: 'active',

                        displayName: decoded.username || decoded.sub,
                        email: decoded.email || '',
                        createdAt: decoded.iat ? decoded.iat * 1000 : Date.now(),
                        lastLoginAt: Date.now(),
                        enabled: true
                    };
                    setUserData(userData);
                }
            }

            localStorage.setItem(STORAGE_KEYS.IS_AUTHENTICATED, 'true');

            // Store refresh token if provided
            if (authData.refreshToken) {
                setRefreshToken(authData.refreshToken);
            }

            return true;
        } else {
            // 服务器返回了成功响应，但登录失败
            message.error(response.message || '登录失败：用户名或密码错误');
            return false;
        }
    } catch (error: any) {
        console.error('Login error:', error);
        message.error(error.message || '登录失败，请检查网络连接');
        return false;
    }
};

export const logoutWithJWT = async (): Promise<void> => {
    try {
        const token = getToken();
        if (token) {
            await post(API.AUTH.LOGOUT, {token});
        }
    } catch (error) {
        console.error('Logout error:', error);
    } finally {
        // Always clear local auth data regardless of API response
        removeToken();
        removeRefreshToken();
        localStorage.removeItem(STORAGE_KEYS.USER);
        localStorage.removeItem(STORAGE_KEYS.IS_AUTHENTICATED);
    }
};

// Check if we need to refresh the token
export const checkAndRefreshToken = async (): Promise<boolean> => {
    if (isTokenExpired()) {
        const newToken = await refreshToken();
        return !!newToken;
    }
    return true;
}; 